/**
 * @file kvServer.h
 * @brief KV 存储服务器类定义
 * 
 * 基于 Raft 共识算法实现的分布式键值存储服务器
 * 提供 Get、Put、Append 操作，保证强一致性
 * 支持快照机制进行日志压缩，提高系统性能
 */
#ifndef SKIP_LIST_ON_RAFT_KVSERVER_H
#define SKIP_LIST_ON_RAFT_KVSERVER_H

#include <boost/any.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/foreach.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/unordered_map.hpp>
#include <boost/serialization/vector.hpp>
#include <iostream>
#include <mutex>
#include <unordered_map>
#include "kvServerRPC.pb.h"
#include "raft.h"
#include "skipList.h"

/**
 * @class KvServer
 * @brief 基于 Raft 的分布式键值存储服务器
 * 
 * 该类实现了一个分布式键值存储系统，使用 Raft 共识算法确保数据一致性。
 * 主要特性：
 * - 支持 Get、Put、Append 操作
 * - 基于 Raft 算法保证强一致性
 * - 支持快照机制进行日志压缩
 * - 提供 RPC 接口供客户端调用
 * - 支持重复请求检测和幂等性保证
 */
class KvServer : raftKVRpcProctoc::kvServerRpc {
 private:
  std::mutex m_mtx;                                     ///< 互斥锁，保证线程安全
  int m_me;                                             ///< 当前服务器节点 ID
  std::shared_ptr<Raft> m_raftNode;                    ///< Raft 共识节点
  std::shared_ptr<LockQueue<ApplyMsg> > applyChan;     ///< kvServer 和 raft 节点的通信管道
  int m_maxRaftState;                                   ///< 日志大小阈值，超过此值时创建快照

  // ========== 数据存储相关 ==========
  std::string m_serializedKVData;                      ///< 序列化后的 KV 数据，用于快照存储
  SkipList<std::string, std::string> m_skipList;       ///< 跳表实现的 KV 存储引擎
  std::unordered_map<std::string, std::string> m_kvDB; ///< 哈希表实现的 KV 数据库

  // ========== 请求处理相关 ==========
  std::unordered_map<int, LockQueue<Op> *> waitApplyCh; ///< 等待应用的命令通道，索引 -> 操作队列
  std::unordered_map<std::string, int> m_lastRequestId; ///< 客户端最后请求 ID，用于重复检测

  // ========== 快照相关 ==========
  int m_lastSnapShotRaftLogIndex;                       ///< 最后一次快照对应的 Raft 日志索引

 public:
  KvServer() = delete;  ///< 禁用默认构造函数

  /**
   * @brief 构造函数
   * @param me 节点 ID
   * @param maxraftstate 最大 Raft 状态大小，超过时触发快照
   * @param nodeInforFileName 节点信息文件名
   * @param port 服务端口号
   */
  KvServer(int me, int maxraftstate, std::string nodeInforFileName, short port);

  /**
   * @brief 启动 KV 服务器
   * 初始化 RPC 服务并开始监听客户端请求
   */
  void StartKVServer();

  /**
   * @brief 调试输出 KV 数据库内容
   * 打印当前数据库中的所有键值对
   */
  void DprintfKVDB();

  /**
   * @brief 在 KV 数据库上执行 Append 操作
   * @param op 操作对象，包含键、值等信息
   */
  void ExecuteAppendOpOnKVDB(Op op);

  /**
   * @brief 在 KV 数据库上执行 Get 操作
   * @param op 操作对象
   * @param value 输出参数，存储查询到的值
   * @param exist 输出参数，指示键是否存在
   */
  void ExecuteGetOpOnKVDB(Op op, std::string *value, bool *exist);

  /**
   * @brief 在 KV 数据库上执行 Put 操作
   * @param op 操作对象，包含键、值等信息
   */
  void ExecutePutOpOnKVDB(Op op);

  /**
   * @brief 处理客户端 Get 请求
   * @param args Get 请求参数
   * @param reply Get 响应结果
   * 
   * 通过 Raft 共识确保读取的一致性
   */
  void Get(const raftKVRpcProctoc::GetArgs *args, raftKVRpcProctoc::GetReply *reply);

  /**
   * @brief 从 Raft 节点中获取已提交的命令
   * @param message 来自 Raft 的应用消息
   * 
   * 注意：不要误以为是执行【GET】命令，这是处理 Raft 层传来的消息
   */
  void GetCommandFromRaft(ApplyMsg message);

  /**
   * @brief 检查请求是否重复
   * @param ClientId 客户端 ID
   * @param RequestId 请求 ID
   * @return true 表示重复请求，false 表示新请求
   */
  bool ifRequestDuplicate(std::string ClientId, int RequestId);

  /**
   * @brief 处理客户端 Put/Append 请求
   * @param args Put/Append 请求参数
   * @param reply Put/Append 响应结果
   * 
   * 通过 Raft 共识确保操作的一致性和持久性
   */
  void PutAppend(const raftKVRpcProctoc::PutAppendArgs *args, raftKVRpcProctoc::PutAppendReply *reply);

  /**
   * @brief 循环读取 Raft 应用命令
   * 持续监听来自 Raft 层的已提交命令并执行
   */
  void ReadRaftApplyCommandLoop();

  /**
   * @brief 从快照中恢复数据
   * @param snapshot 快照数据
   * 
   * 将快照数据反序列化并恢复到 KV 数据库中
   */
  void ReadSnapShotToInstall(std::string snapshot);

  /**
   * @brief 向等待通道发送消息
   * @param op 操作对象
   * @param raftIndex Raft 日志索引
   * @return true 表示发送成功，false 表示失败
   */
  bool SendMessageToWaitChan(const Op &op, int raftIndex);

  /**
   * @brief 检查是否需要创建快照
   * @param raftIndex 当前 Raft 日志索引
   * @param proportion 快照触发比例
   * 
   * 当日志大小超过阈值时，向 Raft 层发送快照命令
   */
  void IfNeedToSendSnapShotCommand(int raftIndex, int proportion);

  /**
   * @brief 处理来自 Raft 的快照消息
   * @param message 快照应用消息
   * 
   * 安装来自 Raft 层的快照数据
   */
  void GetSnapShotFromRaft(ApplyMsg message);

  /**
   * @brief 创建快照
   * @return 序列化后的快照数据
   * 
   * 将当前 KV 数据库状态序列化为快照
   */
  std::string MakeSnapShot();

 public:  // ========== RPC 接口 ==========
  /**
   * @brief Put/Append RPC 接口实现
   * @param controller RPC 控制器
   * @param request 请求参数
   * @param response 响应结果
   * @param done 完成回调
   */
  void PutAppend(google::protobuf::RpcController *controller, const ::raftKVRpcProctoc::PutAppendArgs *request,
                 ::raftKVRpcProctoc::PutAppendReply *response, ::google::protobuf::Closure *done) override;

  /**
   * @brief Get RPC 接口实现
   * @param controller RPC 控制器
   * @param request 请求参数
   * @param response 响应结果
   * @param done 完成回调
   */
  void Get(google::protobuf::RpcController *controller, const ::raftKVRpcProctoc::GetArgs *request,
           ::raftKVRpcProctoc::GetReply *response, ::google::protobuf::Closure *done) override;

  // ========== 序列化相关 ==========
 private:
  friend class boost::serialization::access;

  /**
   * @brief 序列化函数
   * @param ar 归档对象
   * @param version 版本号
   * 
   * 定义需要序列化和反序列化的字段
   * 当 Archive 对应输出归档时，& 操作符类似于 <<
   * 当 Archive 对应输入归档时，& 操作符类似于 >>
   */
  template <class Archive>
  void serialize(Archive &ar, const unsigned int version) {
    ar &m_serializedKVData;  // 序列化 KV 数据
    ar &m_lastRequestId;     // 序列化最后请求 ID 映射
  }

  /**
   * @brief 获取快照数据
   * @return 序列化后的快照字符串
   * 
   * 将当前对象状态序列化为字符串格式的快照
   */
  std::string getSnapshotData() {
    m_serializedKVData = m_skipList.dump_file();  // 导出跳表数据
    std::stringstream ss;
    boost::archive::text_oarchive oa(ss);
    oa << *this;  // 序列化当前对象
    m_serializedKVData.clear();
    return ss.str();
  }

  /**
   * @brief 从字符串解析快照数据
   * @param str 快照字符串
   * 
   * 从序列化的字符串中恢复对象状态
   */
  void parseFromString(const std::string &str) {
    std::stringstream ss(str);
    boost::archive::text_iarchive ia(ss);
    ia >> *this;  // 反序列化到当前对象
    m_skipList.load_file(m_serializedKVData);  // 加载跳表数据
    m_serializedKVData.clear();
  }
};

#endif  // SKIP_LIST_ON_RAFT_KVSERVER_H
